use std::time::{SystemTime, UNIX_EPOCH};
use serde::{Serialize, Deserialize};
use jsonwebtoken::{encode, decode, Header, Algorithm, Validation, EncodingKey, DecodingKey};

/// Our claims struct, it needs to derive `Serialize` and/or `Deserialize`
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String,
    company: String,
    exp: usize,
}

/// 编码，生成 JWT 令牌，必须设置 JWT 的幼小时长（exp） 否则解码时会失败。
pub fn generate_token(claims: Claims, secret: &String) -> String {
    // 自定义头 header 和更改 algorithm 算法
    // 默认头只设置了 typ 和 alg 字段，其中 typ 字段默认值为 JWT，alg 字段默认值为 HS256。
    let mut header = Header::new(Algorithm::HS512);
    header.kid = Some("blabla".to_owned());
    let token = encode(&header, &claims, &EncodingKey::from_secret("secret".as_ref())).unwrap();


    // HS256
    // 默认算法是 HS256，它使用共享密钥。
    // Header::default() 使用默认算法 HS256 返回 JWT 标头
    let token = encode(&Header::default(), &claims, &EncodingKey::from_secret(secret.as_bytes())).unwrap();
    println!("HS256 token: {}", token);

    // 常用于生成证书签名，通过私钥签名，公钥验证。
    // RSA 常用于生产环境，需要生成私钥和公钥，并将公钥配置到服务器。证书的私钥用于签名，公钥用于验证。
    // let token = encode(&Header::new(Algorithm::RS256), &claims, &EncodingKey::from_rsa_pem(include_bytes!("private.pem")).unwrap()).unwrap();
    // println!("RSA token: {}", token);

    // 使用 HS256、HS384 或 HS512 时，密钥始终是共享密钥，如上例所示。使用 RSA/EC 时，密钥应始终是 PEM 或 DER 格式的私人密钥内容。
    // 如果密钥是 PEM 格式，那么在 lazy_static 或类似文件中生成一次 EncodingKey 并重复使用，性能会更好。
    // 注意：不要将私钥内容直接放在代码中，应使用环境变量或文件读取的方式获取。
    return token;
}

/// 解码，解析 JWT 令牌
pub fn decode_token(token: String, secret: &String) -> Result<Claims, jsonwebtoken::errors::Error> {
    // let validation = Validation::new(Algorithm::HS256);
    // let decoded_token = decode::<Claims>(&token, &DecodingKey::from_secret(secret.as_bytes()), &validation).unwrap();

    // 'token' 是一个包含 2 个字段的结构体：'header' 和 'claims'，其中 'claims' 是你自己的结构体。
    let decoded_token = decode::<Claims>(&token, &DecodingKey::from_secret(secret.as_bytes()), &Validation::default()).unwrap();

    // 验证 token 有效性，默认验证算法是 HS256，验证通过返回 Claims 结构体。
    return Ok(decoded_token.claims);
}


// 生成 JWT 令牌，必须设置 JWT 的幼小时长（exp） 否则解码时会失败。
pub fn generate_token_test() {
    // 定义一个过期时间，比如 10 分钟后
    let expiration_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() + 10 * 60;

    // 创建 JWT payload
    let claims = Claims {
        sub: "1234567890".to_string(),
        company: "ACME".to_string(),
        exp: expiration_time as usize,

    };
    let secret = "secret".to_string();
    let token = generate_token(claims, &secret);
    println!("token: {}", token);

    let decoded_token = decode_token(token, &secret).unwrap();
    println!("decoded_token: {:?}", decoded_token);
}